﻿using System;
using System.Collections.Generic;
using UnityEngine;
using VoxelBlock.VoxelBlock3D;
using VoxelBlock;
using Vector3Int = VoxelBlock.Vector3Int;

public class OperationImplementSliceSelect : OperationImplement
{

    Vector3Int[] zeroVector3Int = new Vector3Int[0];
    /// <summary>
    /// 尝试性修改
    /// </summary>
    Dictionary<Vector3Int, int> attemptDictionaryVoxels = new Dictionary<Vector3Int, int>();

    int oldlayer = 0;

    int sliceLayer = 0;

    int startLayer = 0;
    GameObject meshSliceCollider;
    Transform mainCameraY;


    /// <summary>
    /// 一样的颜色才可以
    /// </summary>
    int mSliceUVxy;
    /// <summary>
    /// 对一片进行操作时保存6个方向中的一个
    /// </summary>
    VoxelDirection sliceDirection;

    Func<VoxelDirection> SetSliceDirection;

    /// <summary>
    /// 对一片进行操作时保存6个方向中的一个
    /// </summary>
    Vector3Int MeshSliceXYZ = new Vector3Int();
    Dictionary<Vector3Int, int> mSlicesBlocks = new Dictionary<Vector3Int, int>();

    StartSliceArg startSliceArg = new StartSliceArg();
    VoxelCategories.OperationSelectOperator selectOperator;

    public OperationImplementSliceSelect(GameObject meshSliceCollider
        , Transform mainCameraY, Func<VoxelDirection> setSliceDirection
        )
    {
        this.meshSliceCollider = meshSliceCollider;
        this.mainCameraY = mainCameraY;
        this.SetSliceDirection = setSliceDirection;
    }


    public override void Start(StartArg arg)
    {
        this.selectOperator = arg.selectOperator;
        startSliceArg = arg.startSliceArg;
        base.Start(arg);

        sliceDirection = SetSliceDirection();

        Vector3 bPosition = arg.StartPosition;
        meshSliceCollider.gameObject.SetActive(true);
        meshSliceCollider.transform.position = bPosition;// new Vector3();
        switch (sliceDirection)
        {
            case VoxelDirection.Right:
                //bPosition -= new Vector3(1, 0, 0);
                meshSliceCollider.transform.eulerAngles = new Vector3(90, 0, 0);
                startLayer = (int)bPosition.x;
                break;
            case VoxelDirection.Left:
                //bPosition += new Vector3(1, 0, 0);
                startLayer = (int)bPosition.x;
                meshSliceCollider.transform.eulerAngles = new Vector3(90, 0, 0);
                break;
            case VoxelDirection.Up:
                //bPosition -= new Vector3(0, 1, 0);
                startLayer = (int)bPosition.y;
                meshSliceCollider.transform.eulerAngles = new Vector3(0, mainCameraY.eulerAngles.y, 0);
                break;
            case VoxelDirection.Down:
                //bPosition += new Vector3(0, 1, 0);
                startLayer = (int)bPosition.y;
                meshSliceCollider.transform.eulerAngles = new Vector3(0, mainCameraY.eulerAngles.y, 0);
                break;
            case VoxelDirection.Front:
                //bPosition -= new Vector3(0, 0, 1);
                meshSliceCollider.transform.eulerAngles = new Vector3(90, 0, 0);
                startLayer = (int)bPosition.z;
                break;
            case VoxelDirection.Break:
                //bPosition += new Vector3(0, 0, 1);
                meshSliceCollider.transform.eulerAngles = new Vector3(90, 0, 0);
                startLayer = (int)bPosition.z;
                break;
            default:
                break;
        }

        if (!nowDrawVoxel3DCore.allVoxels.ContainsKey(bPosition))
        {
            return;
        }
        mSlicesBlocks = new Dictionary<Vector3Int, int>();
        mSliceUVxy = nowDrawVoxel3DCore.allVoxels[bPosition].uvKey;
        //BasicAlgorithm.GetSliceBlock(mSlicesBlocks, sliceDirection, bPosition, mSliceUVxy, nowDrawVoxel3DCore.allVoxels);
        BasicAlgorithm.GetSliceBlock(mSlicesBlocks, sliceDirection, bPosition, mSliceUVxy, nowDrawVoxel3DCore.allVoxels, startSliceArg.Is8, startSliceArg.GetColor);

        switch (sliceDirection)
        {
            case VoxelDirection.Right:
                MeshSliceXYZ = new Vector3Int(1, 0, 0);
                break;
            case VoxelDirection.Left:
                MeshSliceXYZ = new Vector3Int(-1, 0, 0);
                break;
            case VoxelDirection.Up:
                MeshSliceXYZ = new Vector3Int(0, 1, 0);
                break;
            case VoxelDirection.Down:
                MeshSliceXYZ = new Vector3Int(0, -1, 0);
                break;
            case VoxelDirection.Front:
                MeshSliceXYZ = new Vector3Int(0, 0, 1);
                break;
            case VoxelDirection.Break:
                MeshSliceXYZ = new Vector3Int(0, 0, -1);
                break;
        }
        switch (sliceDirection)
        {
            case VoxelDirection.Right:
                oldlayer = (int)bPosition.x - startLayer;
                break;
            case VoxelDirection.Left:
                oldlayer = -(int)bPosition.x + startLayer;
                break;
            case VoxelDirection.Up:
                oldlayer = (int)bPosition.y - startLayer;
                break;
            case VoxelDirection.Down:
                oldlayer = -(int)bPosition.y + startLayer;
                break;
            case VoxelDirection.Front:
                oldlayer = (int)bPosition.z - startLayer;
                break;
            case VoxelDirection.Break:
                oldlayer = -(int)bPosition.z + startLayer;
                break;
        }
        oldlayer--;
        List<Vector3Int> arrayVector3Int = new List<Vector3Int>(mSlicesBlocks.Count);
        foreach (Vector3Int position in mSlicesBlocks.Keys)
        {
            Voxel3D voxel;
            if ((!attemptDictionaryVoxels.ContainsKey(position)) && nowDrawVoxel3DCore.allVoxels.TryGetValue(position, out voxel))
            {
                switch (selectOperator)
                {
                    case VoxelCategories.OperationSelectOperator.Union:
                        if (voxel.selectKey == 255)
                        {
                            arrayVector3Int.Add(position);
                            attemptDictionaryVoxels[position] = voxel.selectKey;
                        }
                        break;
                    case VoxelCategories.OperationSelectOperator.Remove:
                        if (voxel.selectKey == 1)
                        {
                            nowDrawVoxel3DCore.DrawSelect(arrayVector3Int, 255);
                            arrayVector3Int.Add(position);
                            attemptDictionaryVoxels[position] = voxel.selectKey;
                        };
                        break;
                }
            }
        }
        switch (selectOperator)
        {
            case VoxelCategories.OperationSelectOperator.Union:
                nowDrawVoxel3DCore.DrawSelect(arrayVector3Int, 1);
                break;
            case VoxelCategories.OperationSelectOperator.Remove:
                nowDrawVoxel3DCore.DrawSelect(arrayVector3Int, 255);
                break;
        }
    }

    public override void Run(RunArg arg)
    {
        RunMethod(arg.nowSelectPosition, arg.nowSelectUVKey);
    }

    private void RunMethod(Vector3Int nowSelectPosition, int nowSelectUVKey)
    {
        Vector3Int bPosition = nowSelectPosition;
        switch (sliceDirection)
        {
            case VoxelDirection.Right:
                sliceLayer = (int)bPosition.x - startLayer;
                break;
            case VoxelDirection.Left:
                sliceLayer = -(int)bPosition.x + startLayer;
                break;
            case VoxelDirection.Up:
                sliceLayer = (int)bPosition.y - startLayer;
                break;
            case VoxelDirection.Down:
                sliceLayer = -(int)bPosition.y + startLayer;
                break;
            case VoxelDirection.Front:
                sliceLayer = (int)bPosition.z - startLayer;
                break;
            case VoxelDirection.Break:
                sliceLayer = -(int)bPosition.z + startLayer;
                break;
        }
        sliceLayer--;
        if (oldlayer == sliceLayer || sliceLayer >= 0)
        {
            return;
        }

        if (oldlayer < sliceLayer)
        {
            List<Vector3Int> arrayVoxel3D = new List<Vector3Int>(mSlicesBlocks.Count * (sliceLayer - oldlayer));
            for (int i = oldlayer + 1; i <= sliceLayer; i++)
            {
                foreach (Vector3Int position in mSlicesBlocks.Keys)
                {
                    Vector3Int key = position + MeshSliceXYZ * i;
                    if (attemptDictionaryVoxels.ContainsKey(key))
                    {
                        arrayVoxel3D.Add(key);
                        attemptDictionaryVoxels.Remove(key);
                    }
                }
            }
            //for (int i = oldlayer + 1; i <= sliceLayer; i++)
            //{
            //    foreach (Vector3Int position in mSlicesBlocks.Keys)
            //    {
            //        int uvKey;
            //        Vector3Int key = position + MeshSliceXYZ * i;
            //        if (attemptDictionaryVoxels.TryGetValue(key, out uvKey))
            //        {
            //            arrayVoxel3D.Add(key);
            //            attemptDictionaryVoxels.Remove(key);
            //        }
            //    }
            //}
            switch (selectOperator)
            {
                case VoxelCategories.OperationSelectOperator.Union:
                    nowDrawVoxel3DCore.DrawSelect(arrayVoxel3D, 255);
                    break;
                case VoxelCategories.OperationSelectOperator.Remove:
                    nowDrawVoxel3DCore.DrawSelect(arrayVoxel3D, 1);
                    break;
            }
        }
        else
        {
            List<Vector3Int> arrayVector3Int = new List<Vector3Int>(mSlicesBlocks.Count * (oldlayer - sliceLayer));
            for (int i = oldlayer; i >= sliceLayer + 1; i--)
            {
                foreach (Vector3Int position in mSlicesBlocks.Keys)
                {
                    Vector3Int key = position + MeshSliceXYZ * i;
                    Voxel3D voxel;
                    if ((!attemptDictionaryVoxels.ContainsKey(key)) && nowDrawVoxel3DCore.allVoxels.TryGetValue(key, out voxel))
                    {
                        switch (selectOperator)
                        {
                            case VoxelCategories.OperationSelectOperator.Union:
                                if (voxel.selectKey == 255)
                                {
                                    arrayVector3Int.Add(key);
                                    attemptDictionaryVoxels[key] = voxel.selectKey;
                                }
                                break;
                            case VoxelCategories.OperationSelectOperator.Remove:
                                if (voxel.selectKey == 1)
                                {
                                    nowDrawVoxel3DCore.DrawSelect(arrayVector3Int, 255);
                                    arrayVector3Int.Add(key);
                                    attemptDictionaryVoxels[key] = voxel.selectKey;
                                };
                                break;
                        }
                    }
                }
            }
            //nowDrawVoxel3DCore.DrawPaintBlock(arrayVector3Int, nowSelectUVKey);
            switch (selectOperator)
            {
                case VoxelCategories.OperationSelectOperator.Union:
                    nowDrawVoxel3DCore.DrawSelect(arrayVector3Int, 1);
                    break;
                case VoxelCategories.OperationSelectOperator.Remove:
                    nowDrawVoxel3DCore.DrawSelect(arrayVector3Int, 255);
                    break;
            }
        }

        oldlayer = sliceLayer;
    }

    public override void Over(OverArg arg)
    {
        meshSliceCollider.gameObject.SetActive(false);
        if (isStop)
        {
            if (attemptDictionaryVoxels.Count > 0)
            {
                List<Vector3Int> serializeVoxel = new List<Vector3Int>(attemptDictionaryVoxels.Count);
                foreach (var item in attemptDictionaryVoxels)
                {
                    if (item.Value != arg.nowSelectUVKey)
                    {
                        serializeVoxel.Add(item.Key);
                    }
                }
                switch (selectOperator)
                {
                    case VoxelCategories.OperationSelectOperator.Union:
                        proxy.Write(VoxelCategories.Operation.SelectAdd, zeroVector3Int, serializeVoxel);
                        break;
                    case VoxelCategories.OperationSelectOperator.Remove:
                        proxy.Write(VoxelCategories.Operation.SelectRemove, serializeVoxel, zeroVector3Int);
                        break;
                }
                attemptDictionaryVoxels.Clear();
            }
        }
        else
        {
            if (attemptDictionaryVoxels.Count > 0)
            {
                List<Vector3Int> serializeVoxel = new List<Vector3Int>(attemptDictionaryVoxels.Count);
                foreach (var item in attemptDictionaryVoxels)
                {
                    if (item.Value != arg.nowSelectUVKey)
                    {
                        serializeVoxel.Add(item.Key);
                    }
                }
                switch (selectOperator)
                {
                    case VoxelCategories.OperationSelectOperator.Union:
                        proxy.Write(VoxelCategories.Operation.SelectAdd, zeroVector3Int, serializeVoxel);
                        break;
                    case VoxelCategories.OperationSelectOperator.Remove:
                        proxy.Write(VoxelCategories.Operation.SelectRemove, serializeVoxel, zeroVector3Int);
                        break;
                }
                attemptDictionaryVoxels.Clear();
            }
            else if (arg.gestureStartPosition == arg.nowSelectPosition)
            {
                List<Vector3Int> arrayVector3Int = new List<Vector3Int>(mSlicesBlocks.Count);
                foreach (Vector3Int position in mSlicesBlocks.Keys)
                {
                    Voxel3D voxel;
                    if ((!attemptDictionaryVoxels.ContainsKey(position)) && nowDrawVoxel3DCore.allVoxels.TryGetValue(position, out voxel))
                    {
                        switch (selectOperator)
                        {
                            case VoxelCategories.OperationSelectOperator.Union:
                                if (voxel.selectKey == 255)
                                {
                                    arrayVector3Int.Add(position);
                                    attemptDictionaryVoxels[position] = voxel.selectKey;
                                }
                                break;
                            case VoxelCategories.OperationSelectOperator.Remove:
                                if (voxel.selectKey == 1)
                                {
                                    nowDrawVoxel3DCore.DrawSelect(arrayVector3Int, 255);
                                    arrayVector3Int.Add(position);
                                    attemptDictionaryVoxels[position] = voxel.selectKey;
                                };
                                break;
                        }
                    }
                }
                switch (selectOperator)
                {
                    case VoxelCategories.OperationSelectOperator.Union:
                        nowDrawVoxel3DCore.DrawSelect(arrayVector3Int, 1);
                        break;
                    case VoxelCategories.OperationSelectOperator.Remove:
                        nowDrawVoxel3DCore.DrawSelect(arrayVector3Int, 255);
                        break;
                }

                List<Vector3Int> serializeVoxel = new List<Vector3Int>(attemptDictionaryVoxels.Count);
                foreach (var item in attemptDictionaryVoxels)
                {
                    if (item.Value != arg.nowSelectUVKey)
                    {
                        serializeVoxel.Add(item.Key);
                    }
                }
                switch (selectOperator)
                {
                    case VoxelCategories.OperationSelectOperator.Union:
                        proxy.Write(VoxelCategories.Operation.SelectAdd, zeroVector3Int, serializeVoxel);
                        break;
                    case VoxelCategories.OperationSelectOperator.Remove:
                        proxy.Write(VoxelCategories.Operation.SelectRemove, serializeVoxel, zeroVector3Int);
                        break;
                }
                attemptDictionaryVoxels.Clear();
            }
        }
    }

}


